package com.taotao.slink.service.impl;

import com.gitee.fastmybatis.core.EqualColumn;
import com.gitee.fastmybatis.core.query.Query;
import com.github.pagehelper.Page;
import com.google.common.base.Preconditions;
import com.taotao.common.Pagination;
import com.taotao.common.redis.RedisClient;
import com.taotao.slink.mapper.ShortLinkMapper;
import com.taotao.slink.model.dto.Link;
import com.taotao.slink.model.entity.ShortLink;
import com.taotao.slink.service.ShortLinkService;
import com.taotao.slink.utils.SlinkRedisKeys;
import com.taotao.slink.utils.SlinkUtils;
import com.taotao.sys.model.vo.sl.ShortLinkPageParam;
import com.taotao.sys.model.vo.sl.ShortLinkPageVO;
import com.taotao.util.ConvertUtils;
import com.taotao.util.EntityUtils;
import com.taotao.util.ValidatorUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

/**
 * <p>
 * 短链接服务接口实现类
 * </p>
 *
 * @author youbeiwuhuan
 * @version V1.0
 * @since 2023-06-26 14:36:20
 */
@Slf4j
@Service
public class ShortLinkServiceImpl implements ShortLinkService {
    @Value("${taotao.short-link-preffix}")
    private String shorLinkPreffix;
    @Resource
    private ShortLinkMapper shortLinkMapper;
    @Autowired
    private RedisClient redisClient;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public String addShortLink(Link link, Long userId) {
        Preconditions.checkArgument(null != userId);
        Preconditions.checkArgument(null != link);
        ValidatorUtils.validateObj(link);


        String linkCode = SlinkUtils.createShortLinkCode(link.getSrcLink());

        while (true) {
            // 存在直接返回
            ShortLink lk = shortLinkMapper.getByColumn("src_link", link.getSrcLink());
            if (null != lk) {
                return getShortLink(lk.getShortLinkCode());
            }

            if (shortLinkMapper.checkExist("short_link_code", linkCode)) {
                linkCode = SlinkUtils.resolveHashCollision(linkCode);
            }

            try {
                ShortLink sl = new ShortLink();
                EntityUtils.setPo5Field(userId, LocalDateTime.now(), sl);
                sl.setSrcLink(link.getSrcLink());
                sl.setShortLinkCode(linkCode);
                shortLinkMapper.saveIgnoreNull(sl);
                return getShortLink(sl.getShortLinkCode());
            } catch (DuplicateKeyException e) {
                // short_link_code 上唯一索引
            }
        }
    }


    private String getShortLink(String shortLinkCode) {

        return shorLinkPreffix + shortLinkCode;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delShortLink(Set<Long> ids, Long userId) {
        Preconditions.checkArgument(null != userId);
        Preconditions.checkArgument(!CollectionUtils.isEmpty(ids));

        List<ShortLink> lks = shortLinkMapper.listByIds(ids);
        if (CollectionUtils.isEmpty(lks)) {
            return;
        }

        shortLinkMapper.deleteByIds(ids, new EqualColumn("update_id", userId), new EqualColumn("update_time", LocalDateTime.now()));
        for (ShortLink l : lks) {
            redisClient.del(SlinkRedisKeys.getSlinkPriffix(l.getShortLinkCode()));
        }


    }

    @Override
    public void loadAllShortLink() {
        List<ShortLink> lks = shortLinkMapper.list(new Query());
        if (CollectionUtils.isEmpty(lks)) {
            return;
        }

        for (ShortLink l : lks) {
            redisClient.set(SlinkRedisKeys.getSlinkPriffix(l.getShortLinkCode()), l.getSrcLink());
        }

    }

    @Override
    public String getSrcLink(String linkCode) {
        Preconditions.checkArgument(null != linkCode);

        String lks = redisClient.get(SlinkRedisKeys.getSlinkPriffix(linkCode));
        if (StringUtils.isNotBlank(lks)) {
            return lks;
        }

        ShortLink lk = shortLinkMapper.getByColumn("short_link_code", linkCode);
        if (null != lk) {
            redisClient.set(SlinkRedisKeys.getSlinkPriffix(lk.getShortLinkCode()), lk.getSrcLink());
            return getShortLink(lk.getShortLinkCode());
        }

        return null;
    }

    @Override
    public Pagination<ShortLinkPageVO> pageList(ShortLinkPageParam param) {
        Preconditions.checkArgument(null != param);

        Page<ShortLink> page = shortLinkMapper.selectByPage(param, param.getPageNum(), param.getPageSize());
        return ConvertUtils.page2Pagination(page, new ConvertUtils.Convertor<ShortLink, ShortLinkPageVO>() {
            @Override
            public ShortLinkPageVO convert(ShortLink shortLink) {
                ShortLinkPageVO vo = new ShortLinkPageVO();
                BeanUtils.copyProperties(shortLink, vo);
                vo.setShortLink(shorLinkPreffix + vo.getShortLinkCode());
                return vo;
            }
        });
    }


}
